package com.macro.edu.utils;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.BeetlTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import com.macro.edu.config.GeneratorConfig;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: Xiao Hai
 * @Date: 2021-04-17 22:42:30
 * @Description: 代码生成器核心文件
 */
public class GeneratorUtils {

    /**
     * 数据连接信息
     * @param dbType 数据库类型
     * @param dbUrl 连接地址
     * @param username 用户名
     * @param password 密码
     * @param driver 驱动
     * @return DataSourceConfig
     */
    private static DataSourceConfig dataSourceConfig(DbType dbType, String dbUrl, String username, String password, String driver) {
        return new DataSourceConfig()
                .setDbType(dbType)
                .setUrl(dbUrl)
                .setUsername(username)
                .setPassword(password)
                .setDriverName(driver)
                ;
    }

    // 配置
    private static GlobalConfig globalConfig() {
        return new GlobalConfig()
                .setAuthor(GeneratorConfig.AUTHOR)
                .setOutputDir(GeneratorConfig.OUTPUT_DIR)
                .setFileOverride(true) // 是否覆盖已有文件
                //.setOpen(true) // 是否打开输出目录
                //.setDateType(DateType.TIME_PACK) // 时间采用java 8，（操作工具类：JavaLib => DateTimeUtils）
                //.setActiveRecord(true)// 不需要ActiveRecord特性的请改为false
                .setEnableCache(false)// XML 二级缓存
                .setBaseResultMap(false)// XML ResultMap
                .setBaseColumnList(false)// XML columList
                .setKotlin(false) //是否生成 kotlin 代码
                // 自定义文件命名，注意 %s 会自动填充表实体属性！
                .setEntityName(GeneratorConfig.FILE_NAME_MODEL)
                .setMapperName(GeneratorConfig.FILE_NAME_DAO)
                .setXmlName(GeneratorConfig.FILE_NAME_XML)
                .setServiceName(GeneratorConfig.FILE_NAME_SERVICE) //去掉Service接口的首字母I
                .setServiceImplName(GeneratorConfig.FILE_NAME_SERVICE_IMPL)
                .setControllerName(GeneratorConfig.FILE_NAME_CONTROLLER)
                .setIdType(IdType.ASSIGN_ID) // 主键类型
                .setDateType(DateType.ONLY_DATE) //定义生成的实体类中日期类型
                .setSwagger2(GeneratorConfig.SWAGGER_SUPPORT) //model swagger2 支持
                ;
//                if (!serviceNameStartWithI)
//                   config.setServiceName("%sService");
    }


    private static StrategyConfig strategyConfig(String [] tablePrefixes, String [] tableNames, String [] fieldPrefixes) {

        //gmt_create get_modified表字段，
        TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT); //自动添加创建时间
        TableFill getModified = new TableFill("get_modified", FieldFill.INSERT_UPDATE); //自动添加更新时间
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(getModified);

        return new StrategyConfig()
                .setCapitalMode(true) // 全局大写命名 ORACLE 注意
                .setSkipView(false) // 是否跳过视图
                //.setDbColumnUnderline(true)
                .setTablePrefix(GeneratorConfig.MODULE_NAME+"_") //设置表前缀不生成
                .setFieldPrefix(fieldPrefixes) // 字段前缀
                .setNaming(NamingStrategy.underline_to_camel) // 表名生成策略
                .setInclude(tableNames)//修改替换成你需要的表名，多个表名传数组
                //.setInclude(Config.MODULE_NAME+"_video") //单表生成
                //.setExclude(new String[]{"test"}) // 排除生成的表
                .setEntityLombokModel(true) // lombok实体
                //.setChainModel(true) // 【实体】是否为构建者模型（默认 false）
                .setEntityColumnConstant(false) // 【实体】是否生成字段常量（默认 false）// 可通过常量名获取数据库字段名 // 3.x支持lambda表达式
                .setLogicDeleteFieldName(GeneratorConfig.FIELD_LOGIC_DELETE_NAME) // 逻辑删除属性名称
                .setVersionFieldName(GeneratorConfig.FIELD_VERSION_NAME) // 乐观锁字段名
                .setEntityTableFieldAnnotationEnable(true) // 开启实体字段注解
                .setLogicDeleteFieldName(GeneratorConfig.DELETE_FIELD_NAME) //逻辑删除字段名
                .setLogicDeleteFieldName(GeneratorConfig.STATUS_FIELD_NAME) //逻辑禁用字段名
                .setEntityBooleanColumnRemoveIsPrefix(true) //去掉布尔值的is_前缀
                .setRestControllerStyle(true) //restful api风格控制器
                .setControllerMappingHyphenStyle(true)  //url中驼峰转连字符 Controller层的地址映射不会出现驼峰命名，以-来分割
                .setTableFillList(tableFills) //自动添加时间或更新时间
                ;



    }






    // 包信息配置
    private static PackageConfig packageConfig(String packageName) {
        return new PackageConfig()
                .setParent(packageName)
                .setController(GeneratorConfig.PACKAGE_NAME_CONTROLLER)
                .setEntity(GeneratorConfig.PACKAGE_NAME_MODEL)
                .setMapper(GeneratorConfig.PACKAGE_NAME_DAO)
                .setXml(GeneratorConfig.DIR_NAME_XML)
                .setService(GeneratorConfig.PACKAGE_NAME_SERVICE)
                .setServiceImpl(GeneratorConfig.PACKAGE_NAME_SERVICE_IMPL)
                ;
    }



    /**
     *
     * @param packageConfig
     * @return
     */
    private static InjectionConfig injectionConfig(final PackageConfig packageConfig) {
        InjectionConfig injectionConfig = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        List<FileOutConfig> fileOutConfigList = new ArrayList<FileOutConfig>();
        fileOutConfigList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                if (StringUtils.isEmpty(packageConfig.getModuleName())) {
                    return GeneratorConfig.PROJECT_PATH + "/src/main/resources/mapper/" + tableInfo.getXmlName() + StringPool.DOT_XML;
                }else {
                    return GeneratorConfig.PROJECT_PATH + "/src/main/resources/mapper/" + packageConfig.getModuleName() + "/" + tableInfo.getXmlName() + StringPool.DOT_XML;
                }
            }
        });
        injectionConfig.setFileOutConfigList(fileOutConfigList);
        return injectionConfig;
    }

    /**
     * 获取模板引擎
     * @return 模板引擎 {@link AbstractTemplateEngine}
     */
    private static AbstractTemplateEngine getTemplateEngine() {
        String templateEngine = GeneratorConfig.TEMPLATE_ENGINE;
        switch (templateEngine) {
            case "velocity":
                return new VelocityTemplateEngine();
            case "freemarker":
                return new FreemarkerTemplateEngine();
            case "beetl":
                return new BeetlTemplateEngine();
        }
        return new VelocityTemplateEngine();
    }

    /**
     * 执行器
     * @param dbType
     * @param dbUrl
     * @param username
     * @param password
     * @param driver
     * @param tablePrefixes
     * @param tableNames
     * @param packageName
     */
    public static void execute(DbType dbType, String dbUrl, String username, String password, String driver, String [] tablePrefixes, String [] tableNames, String packageName, String [] fieldPrefixes) {
        GlobalConfig globalConfig = globalConfig();
        DataSourceConfig dataSourceConfig = dataSourceConfig(dbType, dbUrl, username, password, driver);
        StrategyConfig strategyConfig = strategyConfig(tablePrefixes, tableNames, fieldPrefixes);
        PackageConfig packageConfig = packageConfig(packageName);
//        InjectionConfig injectionConfig = injectionConfig(packageConfig);
        AbstractTemplateEngine templateEngine = getTemplateEngine();
        new AutoGenerator()
                .setGlobalConfig(globalConfig)
                .setDataSource(dataSourceConfig)
                .setStrategy(strategyConfig)
                .setPackageInfo(packageConfig)
                .setTemplateEngine(templateEngine)
                //.setCfg(injectionConfig)
                .execute();
    }
}
